package com.campus.merchant.handler;

import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 原生WebSocket处理器
 * 支持uni-app小程序的原生WebSocket连接
 */
@Component
@Slf4j
public class NativeWebSocketHandler implements WebSocketHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 存储所有WebSocket会话
    private static final CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
    
    // 存储商户ID与WebSocket会话的映射关系
    private static final ConcurrentHashMap<Integer, WebSocketSession> merchantSessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        log.info("WebSocket连接建立，会话ID: {}", session.getId());
        
        // 发送连接成功消息
        sendMessage(session, createMessage("connection", "WebSocket连接成功", null));
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        String payload = message.getPayload().toString();
        log.info("收到WebSocket消息: {}", payload);
        
        try {
            JsonNode jsonNode = objectMapper.readTree(payload);
            String type = jsonNode.get("type").asText();
            
            switch (type) {
                case "test":
                    handleTestMessage(session, jsonNode);
                    break;
                case "heartbeat":
                    handleHeartbeat(session, jsonNode);
                    break;
                case "merchant_connect":
                    handleMerchantConnect(session, jsonNode);
                    break;
                default:
                    log.warn("未知的消息类型: {}", type);
                    break;
            }
        } catch (Exception e) {
            log.error("处理WebSocket消息失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("WebSocket传输错误，会话ID: {}, 错误: {}", session.getId(), exception.getMessage(), exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        sessions.remove(session);
        
        // 从商户会话映射中移除
        merchantSessions.entrySet().removeIf(entry -> entry.getValue().equals(session));
        
        log.info("WebSocket连接关闭，会话ID: {}, 关闭状态: {}", session.getId(), closeStatus);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 处理测试消息
     */
    private void handleTestMessage(WebSocketSession session, JsonNode jsonNode) throws IOException {
        Integer merchantId = jsonNode.get("merchantId").asInt();
        log.info("收到测试消息，商户ID: {}", merchantId);
        
        // 建立商户ID与会话的映射关系
        merchantSessions.put(merchantId, session);
        
        // 响应测试消息
        sendMessage(session, createMessage("test_response", "测试消息接收成功", merchantId));
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(WebSocketSession session, JsonNode jsonNode) throws IOException {
        log.debug("收到心跳消息");
        
        // 响应心跳
        sendMessage(session, createMessage("heartbeat_response", "心跳正常", null));
    }

    /**
     * 处理商户连接消息
     */
    private void handleMerchantConnect(WebSocketSession session, JsonNode jsonNode) throws IOException {
        Integer merchantId = jsonNode.get("merchantId").asInt();
        log.info("商户连接，商户ID: {}", merchantId);
        
        // 建立商户ID与会话的映射关系
        merchantSessions.put(merchantId, session);
        
        // 响应连接成功
        sendMessage(session, createMessage("merchant_connect_response", "商户连接成功", merchantId));
    }

    /**
     * 向指定商户发送订单通知
     */
    public void sendOrderNotification(Integer merchantId, String orderMessage) {
        WebSocketSession session = merchantSessions.get(merchantId);
        if (session != null && session.isOpen()) {
            try {
                String message = createMessage("order_notification", orderMessage, merchantId);
                sendMessage(session, message);
                log.info("向商户{}发送订单通知成功: {}", merchantId, orderMessage);
            } catch (IOException e) {
                log.error("向商户{}发送订单通知失败: {}", merchantId, e.getMessage(), e);
            }
        } else {
            log.warn("商户{}的WebSocket会话不存在或已关闭，无法发送订单通知", merchantId);
        }
    }

    /**
     * 广播系统通知给所有在线商户
     */
    public void broadcastSystemNotification(String message) {
        String notificationMessage = createMessage("system_notification", message, null);
        
        for (WebSocketSession session : sessions) {
            if (session.isOpen()) {
                try {
                    sendMessage(session, notificationMessage);
                } catch (IOException e) {
                    log.error("广播系统通知失败，会话ID: {}, 错误: {}", session.getId(), e.getMessage(), e);
                }
            }
        }
        
        log.info("广播系统通知: {}", message);
    }

    /**
     * 发送消息到WebSocket会话
     */
    private void sendMessage(WebSocketSession session, String message) throws IOException {
        if (session.isOpen()) {
            session.sendMessage(new TextMessage(message));
        }
    }

    /**
     * 创建JSON格式的消息
     */
    private String createMessage(String type, String content, Integer merchantId) {
        try {
            JSONObject json = new JSONObject();
            json.put("type", type);
            json.put("content", content);
            if (merchantId != null) {
                json.put("merchantId", merchantId);
            }
            json.put("timestamp", System.currentTimeMillis());
            return json.toString();
        } catch (Exception e) {
            log.error("创建消息失败: {}", e.getMessage(), e);
            return "{\"type\":\"error\",\"content\":\"消息创建失败\"}";
        }
    }

    /**
     * 获取在线商户数量
     */
    public int getOnlineMerchantCount() {
        return merchantSessions.size();
    }

    /**
     * 获取总连接数
     */
    public int getTotalConnectionCount() {
        return sessions.size();
    }
}